/*********************************************************
          File Name:pisces_process.c
          Author: Abby Cin
          Mail: abbytsing@gmail.com
          Created Time: Fri 24 Apr 2015 09:31:39 PM CST
**********************************************************/

#include "pisces_process.h"

extern void transfer_data(int);
extern int pisces_unblock_socket(int);

void pisces_workprocess(pisces_ctx_t * ctx, int i)
{
    pisces_drop_privilige();
    ctx->child_index = i;
    pisces_signal_t sig_chld;
    sig_chld.signo = SIGCHLD;
    pisces_signal(&sig_chld, SIG_IGN);
    setpgid(getpid(), getpid());
    setpgid(ctx->ch[i].child, ctx->ch[i].child);        /* set process group leader */


    pisces_event_loop(ctx);
    ctx->ch[i].re_make = 1;
}

pid_t pisces_make_workprocess(pisces_ctx_t * ctx, int i)
{
    pid_t pid;

    pid = fork();

    switch (pid) {
    case -1:
        pisces_log(P_LOG_ERR, "fork() failed while creating workprocess %s", strerror(errno));
        return -1;
    case 0:
        pid = getpid();
        pisces_workprocess(ctx, i);
        break;
    default:
        break;
    }

    return pid;
}

void pisces_get_workprocess_id(pisces_ctx_t * ctx)
{
    int i;

    for (i = 0; i < CHILD_NUM; i++) {
        ctx->ch[i].re_make = 0;
        ctx->ch[i].child = pisces_make_workprocess(ctx, i);
    }
    ctx->exit = 0;
}

int pisces_pidfile(pid_t * pid, int op)
{
    FILE *fp = NULL;

    if (op == R_F) {
        if ((fp = fopen(PID_FILE, "r")) == NULL)
            return -1;
        if (fscanf(fp, "%d", pid) == -1)
            return -1;
    } else {
        if ((fp = fopen(PID_FILE, "w")) == NULL)
            return -1;

        if (fprintf(fp, "%d", *pid) == -1)
            return -1;
    }
    fclose(fp);
    return 0;
}

void pisces_renew_workprocess(pisces_ctx_t * ctx)
{
    int i;

    for (i = 0; i < CHILD_NUM; i++) {
        if (ctx->ch[i].re_make == 1) {
            ctx->ch[i].child = pisces_make_workprocess(ctx, i);
            ctx->ch[i].re_make = 0;
        }
    }
    ctx->exit = 0;
}

void pisces_stop(pisces_ctx_t * ctx)
{
    int i;

    pisces_ignore_child();

    for (i = 0; i < CHILD_NUM; i++)
        killpg(ctx->ch[i].child, SIGKILL);

    for (i = 0; i < CHILD_NUM; i++) {
        kill(ctx->ch[i].child, SIGTERM);
        close(ctx->ch[i].confd);        /* ignore error */
        if (ctx->exit == 0)
            ctx->ch[i].re_make = 1;     /* for SIGHUP re-fork() */
    }
    if (ctx->exit == 1) {
        free(ctx->conf->host);
        free(ctx->conf->port);
        free(ctx->conf->root_dir);
        free(ctx->conf);
        free(ctx->loop);
        close(ctx->listenfd);
        free(ctx);
        unlink(PID_FILE);
        exit(0);
    }
}

void pisces_wait_child(void)
{
    while (waitpid(-1, NULL, WNOHANG | WUNTRACED) != -1)
        continue;
}

void pisces_ignore_child(void)
{
    pisces_signal_t sig_chld;
    sig_chld.signo = SIGCHLD;
    pisces_signal(&sig_chld, SIG_IGN);
}

void pisces_master_control(char *argv[])
{
    pid_t pppid;
    if (strcmp(argv[1], "restart") == 0) {
        if (pisces_pidfile(&pppid, R_F) == -1) {
            fprintf(stderr, "%s", strerror(errno));
            exit(1);
        }
        if (kill(pppid, SIGHUP) == -1)
            fprintf(stderr, "sending restart signal to pisces failed, exit...\n");
        else
            printf("pisces restarted\n");
    } else if (strcmp(argv[1], "stop") == 0) {
        if (pisces_pidfile(&pppid, R_F) == -1) {
            fprintf(stderr, "%s", strerror(errno));
            exit(1);
        }
        if (kill(pppid, SIGTERM) == -1)
            fprintf(stderr, "sending terminal signal to pisces failed, exit...\n");
        else
            printf("pisces stopped\n");
    } else
        fprintf(stderr, "Usage:%s [restart|stop]\n", argv[0]);
    exit(0);
}
